/*
Dependancies:
#include "pThreads/semaphore.h"
#include <vector>
*/

//To enable semaphore debugging you should either uncomment the following line or add 
// __SEMAPHORE_DEBUG_ to your project settings (C/C++ -> preprocessor -> preprocessor definitions)
//#define __SEMAPHORE_DEBUG_

#pragma once

#ifndef _CSEMAPHORE_H_
#define _CSEMAPHORE_H_

#include "pThreads/semaphore.h"
#include <vector>


struct CSemThreadInfo
{
	int threadId;
	int nrPassed;//how many times has the thread passed the semaphore without locking,
	//because it already locked the semaphore before
};

class CSemaphore
{
private:
#ifdef __SEMAPHORE_DEBUG_
	sem_t m_LogMutex;
	FILE* logfile;
	bool m_isDebuggingEnabled;
	bool m_keepLogOpen;
#endif
	sem_t m_ThreadInfoMutex;
	sem_t m_semaphore;
	std::vector<CSemThreadInfo> m_threadInfo;
public:
	//Constructors
	CSemaphore(void);
	CSemaphore(int count);

	CSemaphore(int count, bool debuggingEnabled);
	CSemaphore(int count, bool debuggingEnabled, bool keepLogOpen);
	CSemaphore(bool debuggingEnabled, bool keepLogOpen);
	CSemaphore(bool debuggingEnabled);

	//Destructor
	~CSemaphore(void);

	//unforced Version
	//These Lock/Unlock functions check if the thread locked the semaphore before and let it pass without additional locking
	bool tryLock(void);
	bool lock(void);

	bool lock(bool debuggingEnabled);
	bool unlock(void);
	bool unlock(bool debuggingEnabled);

	bool timedLock(int waitMilliSecs);

	//forced version
	//these don't check if the thread passed the semaphore before
	bool forceTryLock(void);

	bool forceLock(void);
	bool forceLock(bool enableDeadlockDetection);

	bool forceUnlock(void);
	bool CSemaphore::forceUnlock(bool debuggingEnabled);

	bool forceTimedLock(int waitMilliSecs);

	//Debug functions
	int getSemaphoreCounter(void);
#ifdef __SEMAPHORE_DEBUG_
	void logDebugMessage(char* buf ,... );
#endif
};
#endif